<template>
  <div class="app-container">
    <el-row :gutter="10">
      <el-col :span="24" class="card-box">
        <el-card>
          <template #header>
            <Monitor style="width: 1em; height: 1em; vertical-align: middle;" /> 
            <span style="vertical-align: middle;">监控系统状态</span>
            <el-button
              style="float: right; padding: 3px 0"
              type="primary"
              plain
              size="small"
              @click="handleRefresh"
              :loading="loading"
            >
              <el-icon><Refresh /></el-icon> 刷新数据
            </el-button>
            <el-button
              style="float: right; padding: 3px 0; margin-right: 10px;"
              type="warning"
              plain
              size="small"
              @click="handleTestAlert"
              :loading="alertLoading"
            >
              <el-icon><Bell /></el-icon> 测试告警
            </el-button>
          </template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;">
              <thead>
                <tr>
                  <th class="el-table__cell is-leaf"><div class="cell">监控项</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">状态</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">详情</div></th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">Prometheus</div></td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell">
                      <el-tag v-if="prometheusStatus.status === 'down'" type="success">运行中</el-tag>
                      <el-tag v-else type="danger">未运行</el-tag>
                    </div>
                  </td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell">
                      <span v-if="prometheusStatus.status === 'down'">
                        版本: {{ prometheusStatus.version || '未知' }}
                        <el-link type="primary" :href="prometheusStatus.url" target="_blank" style="margin-left: 10px;">访问控制台</el-link>
                      </span>
                      <span v-else>{{ prometheusStatus.error || '无法连接到Prometheus服务' }}</span>
                    </div>
                  </td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">Grafana</div></td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell">
                      <el-tag v-if="grafanaStatus.status === 'up'" type="success">运行中</el-tag>
                      <el-tag v-else type="danger">未运行</el-tag>
                    </div>
                  </td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell">
                      <span v-if="grafanaStatus.status === 'up'">
                        版本: {{ grafanaStatus.version || '未知' }}
                        <el-link type="primary" :href="grafanaStatus.url" target="_blank" style="margin-left: 10px;">访问控制台</el-link>
                      </span>
                      <span v-else>{{ grafanaStatus.error || '无法连接到Grafana服务' }}</span>
                    </div>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>

      <el-col :span="12" class="card-box">
        <el-card>
          <template #header><Cpu style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">CPU指标</span></template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;">
              <thead>
                <tr>
                  <th class="el-table__cell is-leaf"><div class="cell">指标名称</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">当前值</div></th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">CPU使用率</div></td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell" :class="{'text-danger': metrics.cpuUsage > 80}">
                      <el-progress :percentage="metrics.cpuUsage" :color="getColorByCpuUsage(metrics.cpuUsage)"></el-progress>
                    </div>
                  </td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">系统CPU时间</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ metrics.cpuSystem }}秒</div></td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">用户CPU时间</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ metrics.cpuUser }}秒</div></td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">事件循环延迟</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ metrics.eventLoopLag }}毫秒</div></td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>

      <el-col :span="12" class="card-box">
        <el-card>
          <template #header><Tickets style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存指标</span></template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;">
              <thead>
                <tr>
                  <th class="el-table__cell is-leaf"><div class="cell">指标名称</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">当前值</div></th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">内存使用率</div></td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell" :class="{'text-danger': metrics.memoryUsagePercent > 80}">
                      <el-progress :percentage="metrics.memoryUsagePercent" :color="getColorByMemoryUsage(metrics.memoryUsagePercent)"></el-progress>
                    </div>
                  </td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">堆内存使用</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ formatBytes(metrics.heapUsed) }} / {{ formatBytes(metrics.heapTotal) }}</div></td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">常驻内存</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ formatBytes(metrics.rss) }}</div></td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">外部内存</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ formatBytes(metrics.external) }}</div></td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>

      <el-col :span="12" class="card-box">
        <el-card>
          <template #header><DataLine style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">HTTP请求指标</span></template>
          <div ref="httpRequestsChart" style="height: 300px;"></div>
        </el-card>
      </el-col>

      <el-col :span="12" class="card-box">
        <el-card>
          <template #header><Histogram style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">资源使用</span></template>
          <div ref="resourcesChart" style="height: 300px;"></div>
        </el-card>
      </el-col>

      <el-col :span="24" class="card-box">
        <el-card>
          <template #header><Storage style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">磁盘使用情况</span></template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;">
              <thead>
                <tr>
                  <th class="el-table__cell is-leaf"><div class="cell">挂载点</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">已用空间</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">总空间</div></th>
                  <th class="el-table__cell is-leaf"><div class="cell">使用率</div></th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(disk, index) in metrics.disks" :key="index">
                  <td class="el-table__cell is-leaf"><div class="cell">{{ disk.mount }}</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ formatBytes(disk.used) }}</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">{{ formatBytes(disk.total) }}</div></td>
                  <td class="el-table__cell is-leaf">
                    <div class="cell" :class="{'text-danger': disk.usagePercent > 80}">
                      <el-progress :percentage="disk.usagePercent" :color="getColorByDiskUsage(disk.usagePercent)"></el-progress>
                    </div>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { getMetrics, getPrometheusStatus, getGrafanaStatus, sendTestAlert } from '@/api/monitor/metrics'
import * as echarts from 'echarts'

const { proxy } = getCurrentInstance()
const loading = ref(false)
const alertLoading = ref(false)
const metrics = ref({
  cpuUsage: 0,
  cpuSystem: 0,
  cpuUser: 0,
  eventLoopLag: 0,
  memoryUsagePercent: 0,
  heapUsed: 0,
  heapTotal: 0,
  rss: 0,
  external: 0,
  disks: [],
  httpRequests: [],
  resources: {
    handles: [],
    requests: []
  }
})
const prometheusStatus = ref({
  status: 'down',
  version: '',
  url: '',
  error: ''
})
const grafanaStatus = ref({
  status: 'down',
  version: '',
  url: '',
  error: ''
})
const httpRequestsChart = ref(null)
const resourcesChart = ref(null)

function formatBytes(bytes, decimals = 2) {
  if (!bytes) return '0 Bytes'
  
  const k = 1024
  const dm = decimals < 0 ? 0 : decimals
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  
  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
}

function getColorByCpuUsage(usage) {
  if (usage < 50) return '#67C23A'
  if (usage < 80) return '#E6A23C'
  return '#F56C6C'
}

function getColorByMemoryUsage(usage) {
  if (usage < 50) return '#67C23A'
  if (usage < 80) return '#E6A23C'
  return '#F56C6C'
}

function getColorByDiskUsage(usage) {
  if (usage < 50) return '#67C23A'
  if (usage < 80) return '#E6A23C'
  return '#F56C6C'
}

function parseMetricsData(data) {
  // 检查数据是否有效
  if (!data || typeof data !== 'string') {
    console.warn('接收到无效的指标数据格式')
    return {
      cpuUsage: 0,
      cpuSystem: 0,
      cpuUser: 0,
      eventLoopLag: 0,
      memoryUsagePercent: 0,
      heapUsed: 0,
      heapTotal: 0,
      rss: 0,
      external: 0,
      disks: [],
      httpRequests: [],
      resources: {
        handles: [],
        requests: []
      }
    }
  }
  
  const lines = data.split('\n')
  const parsed = {
    cpuUsage: 0,
    cpuSystem: 0,
    cpuUser: 0,
    eventLoopLag: 0,
    memoryUsagePercent: 0,
    heapUsed: 0,
    heapTotal: 0,
    rss: 0,
    external: 0,
    disks: [],
    httpRequests: [],
    resources: {
      handles: [],
      requests: []
    }
  }
  
  try {
    for (const line of lines) {
      if (line.startsWith('#') || !line.trim()) continue
      
      // CPU使用率
      if (line.startsWith('node_cpu_usage_percent')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.cpuUsage = isNaN(value) ? 0 : value
      }
      // CPU系统时间
      else if (line.startsWith('process_cpu_system_seconds_total')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.cpuSystem = isNaN(value) ? 0 : value
      }
      // CPU用户时间
      else if (line.startsWith('process_cpu_user_seconds_total')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.cpuUser = isNaN(value) ? 0 : value
      }
      // 事件循环延迟
      else if (line.startsWith('nodejs_eventloop_lag_seconds')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.eventLoopLag = isNaN(value) ? 0 : value * 1000 // 转换为毫秒
      }
      // 内存使用
      else if (line.startsWith('node_memory_usage_bytes')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.rss = isNaN(value) ? 0 : value
      }
      // 内存总量
      else if (line.startsWith('node_memory_total_bytes')) {
        const value = parseFloat(line.split(' ')[1])
        if (!isNaN(value) && value > 0) {
          parsed.memoryUsagePercent = parseFloat(((parsed.rss / value) * 100).toFixed(2))
        }
      }
      // 堆内存使用
      else if (line.startsWith('nodejs_heap_size_used_bytes')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.heapUsed = isNaN(value) ? 0 : value
      }
      // 堆内存总量
      else if (line.startsWith('nodejs_heap_size_total_bytes')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.heapTotal = isNaN(value) ? 0 : value
      }
      // 外部内存
      else if (line.startsWith('nodejs_external_memory_bytes')) {
        const value = parseFloat(line.split(' ')[1])
        parsed.external = isNaN(value) ? 0 : value
      }
      // 磁盘使用
      else if (line.startsWith('node_disk_usage_bytes')) {
        const match = line.match(/node_disk_usage_bytes{mount="(.+?)"}\s+(.+)/)
        if (match) {
          const mount = match[1]
          const used = parseFloat(match[2])
          const disk = parsed.disks.find(d => d.mount === mount)
          if (disk) {
            disk.used = isNaN(used) ? 0 : used
          } else {
            parsed.disks.push({ mount, used: isNaN(used) ? 0 : used, total: 0, usagePercent: 0 })
          }
        }
      }
      // 磁盘总量
      else if (line.startsWith('node_disk_total_bytes')) {
        const match = line.match(/node_disk_total_bytes{mount="(.+?)"}\s+(.+)/)
        if (match) {
          const mount = match[1]
          const total = parseFloat(match[2])
          const disk = parsed.disks.find(d => d.mount === mount)
          if (disk) {
            disk.total = isNaN(total) ? 0 : total
            if (disk.total > 0) {
              disk.usagePercent = parseFloat(((disk.used / disk.total) * 100).toFixed(2))
            }
          } else {
            parsed.disks.push({ mount, used: 0, total: isNaN(total) ? 0 : total, usagePercent: 0 })
          }
        }
      }
      // HTTP请求统计
      else if (line.startsWith('http_requests_total')) {
        const match = line.match(/http_requests_total{method="(.+?)",route="(.+?)",status_code="(.+?)"}\s+(.+)/)
        if (match) {
          const method = match[1]
          const route = match[2]
          const statusCode = match[3]
          const count = parseFloat(match[4])
          parsed.httpRequests.push({ 
            method, 
            route, 
            statusCode, 
            count: isNaN(count) ? 0 : count 
          })
        }
      }
      // 活跃句柄
      else if (line.startsWith('nodejs_active_handles{')) {
        const match = line.match(/nodejs_active_handles{type="(.+?)"}\s+(.+)/)
        if (match) {
          const type = match[1]
          const count = parseFloat(match[2])
          parsed.resources.handles.push({ 
            type, 
            count: isNaN(count) ? 0 : count 
          })
        }
      }
      // 活跃请求
      else if (line.startsWith('nodejs_active_requests{')) {
        const match = line.match(/nodejs_active_requests{type="(.+?)"}\s+(.+)/)
        if (match) {
          const type = match[1]
          const count = parseFloat(match[2])
          parsed.resources.requests.push({ 
            type, 
            count: isNaN(count) ? 0 : count 
          })
        }
      }
    }
  } catch (error) {
    console.error('解析指标数据时发生错误:', error)
  }
  
  return parsed
}

function loadData() {
  loading.value = true
  proxy.$modal.loading("正在加载监控数据，请稍候！")
  
  // 使用Promise.all但对各个请求单独处理错误
  Promise.all([
    getMetrics().catch(err => {
      console.error("获取指标数据失败:", err)
      return { data: "" } // 返回空字符串作为默认值
    }),
    getPrometheusStatus().catch(err => {
      console.error("获取Prometheus状态失败:", err)
      return { data: { status: 'down', error: '连接失败' } } // 返回默认状态
    }),
    getGrafanaStatus().catch(err => {
      console.error("获取Grafana状态失败:", err)
      return { data: { status: 'down', error: '连接失败' } } // 返回默认状态
    })
  ]).then(([metricsRes, prometheusRes, grafanaRes]) => {
    try {
      // 处理metrics数据，如果无效则使用空字符串
      metrics.value = parseMetricsData(metricsRes.data || "")
      
      // 设置Prometheus状态，确保数据存在
      prometheusStatus.value = prometheusRes.data || { status: 'down', error: '无法获取状态' }
      
      // 设置Grafana状态，确保数据存在
      grafanaStatus.value = grafanaRes.data || { status: 'down', error: '无法获取状态' }
      
      // 渲染图表
      renderHttpRequestsChart()
      renderResourcesChart()
    } catch (error) {
      console.error("处理监控数据失败", error)
      // 设置默认值
      metrics.value = {
        cpuUsage: 0,
        cpuSystem: 0,
        cpuUser: 0,
        eventLoopLag: 0,
        memoryUsagePercent: 0,
        heapUsed: 0,
        heapTotal: 0,
        rss: 0,
        external: 0,
        disks: [],
        httpRequests: [],
        resources: {
          handles: [],
          requests: []
        }
      }
    } finally {
      loading.value = false
      proxy.$modal.closeLoading()
    }
  }).catch(error => {
    console.error("加载监控数据失败", error)
    loading.value = false
    proxy.$modal.closeLoading()
    proxy.$modal.msgError("加载监控数据失败")
  })
}

function handleRefresh() {
  loadData()
}

function handleTestAlert() {
  alertLoading.value = true
  sendTestAlert().then(res => {
    proxy.$modal.msgSuccess("测试告警已发送")
    alertLoading.value = false
  }).catch(() => {
    alertLoading.value = false
  })
}

function renderHttpRequestsChart() {
  try {
    // 确保DOM元素存在
    if (!httpRequestsChart.value) {
      console.warn('HTTP请求图表DOM元素不存在')
      return
    }
    
    const chartInstance = echarts.init(httpRequestsChart.value, 'macarons')
    
    // 处理数据
    const data = metrics.value.httpRequests.map(item => {
      return {
        name: `${item.method} ${item.route}`,
        value: item.count,
        statusCode: item.statusCode
      }
    })
    
    // 没有数据时显示提示信息
    if (data.length === 0) {
      chartInstance.setOption({
        title: {
          text: '暂无HTTP请求数据',
          left: 'center',
          top: 'center'
        }
      })
      return
    }
    
    const option = {
      tooltip: {
        trigger: 'item',
        formatter: '{a} <br/>{b}: {c} 次'
      },
      legend: {
        orient: 'vertical',
        right: 10,
        top: 'center',
        data: data.map(item => item.name)
      },
      series: [
        {
          name: 'HTTP请求',
          type: 'pie',
          radius: ['40%', '70%'],
          avoidLabelOverlap: false,
          itemStyle: {
            borderRadius: 10,
            borderColor: '#fff',
            borderWidth: 2
          },
          label: {
            show: false,
            position: 'center'
          },
          emphasis: {
            label: {
              show: true,
              fontSize: 12,
              fontWeight: 'bold'
            }
          },
          labelLine: {
            show: false
          },
          data: data
        }
      ]
    }
    
    chartInstance.setOption(option)
    window.addEventListener('resize', () => {
      chartInstance.resize()
    })
  } catch (error) {
    console.error('渲染HTTP请求图表失败:', error)
  }
}

function renderResourcesChart() {
  try {
    // 确保DOM元素存在
    if (!resourcesChart.value) {
      console.warn('资源图表DOM元素不存在')
      return
    }
    
    const chartInstance = echarts.init(resourcesChart.value, 'macarons')
    
    // 处理数据
    const handleTypes = metrics.value.resources.handles.map(item => item.type)
    const handleValues = metrics.value.resources.handles.map(item => item.count)
    
    // 没有数据时显示提示信息
    if (handleTypes.length === 0) {
      chartInstance.setOption({
        title: {
          text: '暂无资源使用数据',
          left: 'center',
          top: 'center'
        }
      })
      return
    }
    
    const option = {
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow'
        }
      },
      legend: {
        data: ['活跃句柄']
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
      },
      xAxis: {
        type: 'value'
      },
      yAxis: {
        type: 'category',
        data: handleTypes
      },
      series: [
        {
          name: '活跃句柄',
          type: 'bar',
          data: handleValues
        }
      ]
    }
    
    chartInstance.setOption(option)
    window.addEventListener('resize', () => {
      chartInstance.resize()
    })
  } catch (error) {
    console.error('渲染资源使用图表失败:', error)
  }
}

onMounted(() => {
  loadData()
})
</script>

<style scoped>
.text-danger {
  color: #F56C6C;
}
.card-box {
  margin-bottom: 10px;
}
</style> 